<?php

namespace App\Http\Controllers\PartnerApi;

use App\Enums\AssetStatus;
use App\Enums\ExchangeChannel;
use App\Enums\TransferSource;
use App\Http\Controllers\Controller;
use App\Jobs\TransferJob;
use App\Models\Asset;
use App\Models\FrontendUser;
use App\Models\Product;
use App\Models\ProductConfig;
use App\Models\TransferRecord;
use App\Services\WalletService;
use Illuminate\Support\Arr;
use Vinlon\Laravel\LayAdmin\Exceptions\AdminException;

class HJSController extends Controller
{
    /** @var WalletService */
    private $walletService;

    /**
     * HezhiController constructor.
     */
    public function __construct(WalletService $walletService)
    {
        $this->walletService = $walletService;
    }

    public function register()
    {
        $phoneNo = request()->phoneNumber;
        if (!$phoneNo) {
            return $this->failResponse(1001, '参数 phoneNumber 未找到');
        }

        $user = FrontendUser::query()
            ->where('mobile', $phoneNo)
            ->where('agent_id', request()->agent_id)
            ->first();
        if (!$user) {
            $walletAddress = $this->walletService->openWallet($phoneNo);
            $user = new FrontendUser();
            $user->mobile = $phoneNo;
            $user->nickname = '';
            $user->agent_id = request()->agent_id;
            $user->password = \Hash::make(request()->password);
            $user->wallet_address = $walletAddress;
        }
        $user->save();

        return $this->successResponse([
            'Account' => $user->wallet_address,
            'UserID' => md5($user->id),
        ]);
    }

    /** 查询商品存证 */
    public function listProductTokens()
    {
        if (!request()->externalId) {
            return $this->failResponse(1001, '参数 externalId 未找到');
        }
        $limit = request()->get('ps', 10);
        $page = request()->get('cp', 1);
        if ($limit > 1000) {
            return $this->failResponse(1001, '每次最多查询1000条');
        }
        $product = Product::query()
            ->where('agent_id', request()->agent_id)
            ->where('contract_address', request()->externalId)
            ->first();
        if (!$product) {
            return $this->failResponse(1003, '商品未找到');
        }
        $isLocked = $product->configs()
            ->where('config_key', ProductConfig::IS_LOCKED)
            ->value('config_value');
        if (!$isLocked) {
            return $this->failResponse(1004, '商品未锁定，无法上架到交易所');
        }
        $exchangeChannel = $product->configs()
            ->where('config_key', ProductConfig::EXCHANGE_CHANNEL)
            ->value('config_value');
        if ($exchangeChannel && ExchangeChannel::HJS()->isNot($exchangeChannel)) {
            return $this->failResponse(1004, '交易渠道设置错误，请将交易渠道设置为合交所');
        }

        //查询资产持有列表
        $assetQuery = Asset::query()
            ->with('user')
            ->where('contract_address', $product->contract_address)
            ->where('asset_status', AssetStatus::HOLD);
        $total = $assetQuery->count();
        $assets = $assetQuery
            ->offset($limit * ($page - 1))
            ->limit($limit)
            ->get();

        $list = [];
        foreach ($assets as $asset) {
            $list[] = [
                'Account' => $asset->user->wallet_address,
                'ExternalId' => $asset->contract_address,
                'CertificateCode' => $asset->token_id,
                'CertificateNumber' => $asset->cert_sn,
            ];
        }

        $data = [
            'RecordCount' => $total,
            'TotalPage' => ceil($total / $limit),
            'ItemList' => $list,
        ];

        return $this->successResponse($data);
    }

    /** 批量资产划转 */
    public function batchTransfer()
    {
        request()->validate([
            'data' => 'array | required',
            'data.*.tradeChainCode' => 'required',
            'data.*.sellerAccount' => 'required',
            'data.*.buyerAccount' => 'required',
            'data.*.certificateCode' => 'required',
        ]);
        $data = request()->get('data', []);
        if (0 == count($data)) {
            throw new AdminException('未找到交易划转请求');
        }
        if (count($data) > 100) {
            throw new AdminException('一次最多处理100个资产划转');
        }
        /** @var TransferRecord $existedRecord */
        $existingTransfers = TransferRecord::query()
            ->where('agent_id', request()->agent_id)
            ->whereIn('transfer_sn', Arr::pluck($data, 'tradeChainCode'))
            ->get()->mapWithKeys(function (TransferRecord $record) {
                return [$record->transfer_sn => $record];
            });
        $users = FrontendUser::query()
            ->where('agent_id', request()->agent_id)
            ->whereIn('wallet_address', array_merge(Arr::pluck($data, 'buyerAccount'), Arr::pluck($data, 'sellerAccount')))
            ->get()->mapWithKeys(function (FrontendUser $user) {
                return [$user->wallet_address => $user];
            });

        $assets = Asset::query()
            ->whereIn('token_id', Arr::pluck($data, 'certificateCode'))
            ->where('asset_status', AssetStatus::HOLD)
            ->get()->mapWithKeys(function (Asset $asset) {
                return [$asset->token_id => $asset];
            });

        $toBeTransferred = [];
        foreach ($data as $row) {
            $buyerAddress = Arr::get($row, 'buyerAccount');
            /** @var FrontendUser $buyer */
            $buyer = Arr::get($users, $buyerAddress);
            $sellerAddress = Arr::get($row, 'sellerAccount');
            /** @var FrontendUser $seller */
            $seller = Arr::get($users, $sellerAddress);
            $assetTokenId = Arr::get($row, 'certificateCode');
            /** @var Asset $asset */
            $asset = Arr::get($assets, $assetTokenId);
            $transferSn = Arr::get($row, 'tradeChainCode');

            if ($existingTransfers->has($transferSn)) {
                return $this->failResponse(1001, 'tradeChainCode已存在:' . $transferSn);
            }
            if (!$seller) {
                return $this->failResponse(1001, '无效的卖方账号:' . $sellerAddress);
            }
            if (!$buyer) {
                return $this->failResponse(1001, '无效的买方账号:' . $buyerAddress);
            }
            if (!$asset) {
                return $this->failResponse(1001, '资产未找到:' . $assetTokenId);
            }
            if ($asset->user_id != $seller->id) {
                return $this->failResponse(1001, sprintf('资产%s不属于卖方%s', $asset->token_id, $seller->wallet_address));
            }
            $record = new TransferRecord();
            $record->agent_id = request()->agent_id;
            $record->asset_id = $asset->id;
            $record->to_user_id = $buyer->id;
            $record->source = TransferSource::HJS;
            $record->transfer_sn = $transferSn;
            $record->source_params = json_encode(request()->all());
            $toBeTransferred[] = $record;
        }
        foreach ($toBeTransferred as $transfer) {
            $transfer->save();
            TransferJob::dispatch($transfer);
        }

        return $this->successResponse();
    }

    /** 查询资产划转状态 */
    public function batchQuery()
    {
        request()->validate([
            'tradeChainCodeList' => 'array | required',
        ]);
        $transferSnList = request()->get('tradeChainCodeList', []);
        $transStatus = TransferRecord::query()
            ->where('agent_id', request()->agent_id)
            ->whereIn('transfer_sn', $transferSnList)
            ->get()->mapWithKeys(function (TransferRecord $record) {
                return [$record->transfer_sn => [
                    'status' => $record->status->value,
                    'description' => $record->remark ?: $record->status->description,
                ]];
            });

        $result = [];
        foreach ($transferSnList as $transferSn) {
            $result[$transferSn] = Arr::get($transStatus, $transferSn, [
                'status' => 'not_found',
                'description' => 'tradeChainCode未找到',
            ]);
        }

        return $this->successResponse(['Result' => $result]);
    }

    private function failResponse($code, $msg)
    {
        return [
            'Success' => false,
            'Code' => $code,
            'Description' => $msg,
        ];
    }

    private function successResponse($data)
    {
        return array_merge([
            'Success' => true,
        ], $data);
    }
}
